#ifndef JLUROBOVISION_PLATFORM_H
#define JLUROBOVISION_PLATFORM_H

// 这种PACK宏里面的结构体就不能用逗号了
#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif

#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop))
#endif

#endif //JLUROBOVISION_PLATFORM_H

#ifndef  _SERIAL_H
#define  _SERIAL_H

//串口相关的头文件
#include<stdio.h>      /*标准输入输出定义*/
#include<stdlib.h>     /*标准函数库定义*/
#include <atomic>
#include <mutex>
#include <cstring>
#include <iostream>

#if defined(__linux__)  /* DO NOT INCLUDE UNIX HEAEDERS UNDER WINDOWS */
#include<unistd.h>     /*Unix 标准函数定义*/
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>      /*文件控制定义*/
#include<termios.h>    /*PPSIX 终端控制定义*/
#include<errno.h>      /*错误号定义*/
#endif

#include "../double_buffer/double_buffer.h"

PACK(struct SendStruct
{
    uint8_t frameHead;
    uint8_t cmd;
    uint16_t dataX;
    uint16_t dataY;
    uint8_t frameEnd;
});

PACK(struct ReceiveStruct
{
    uint8_t frameHead;
    uint8_t find;
    uint8_t frameEnd;
});

using namespace std;


class Serial
{
public:

    static Serial* Get();
    
    void SendData(uint8_t cmd,uint16_t datax,uint16_t datay);
    ReceiveStruct GetData();

    static void SerialTask();

    static void OpenSerialPort(int& _fd);

    void SetTakeOffFlag(bool takeoff);
protected:
    Serial();
    static constexpr char receiveFrameHead = 0xAA;
    static constexpr char receiveFrameEnd = 0xBB;
    static constexpr char sendFrameHead = 0xAA;
    static constexpr char sendFrameEnd = 0xBB;
    /*******************************************************************
*名称：             UART0_Open
*功能：             打开串口并返回串口设备文件描述
*入口参数：         fd      文件描述符
                    port    串口号(ttyTHS0,ttyTHS1,ttyTHS2)
*出口参数：正确返回为1，错误返回为0
*******************************************************************/
static int UART0_Open(int fd,char*port);


/*******************************************************************
*名称：             UART0_Close
*功能：             关闭串口并返回串口设备文件描述
*入口参数：         fd          文件描述符
                    port        串口号(ttyS0,ttyS1,ttyS2)
*出口参数：void
*******************************************************************/
static void UART0_Close(int fd);

/*******************************************************************
*名称：             UART0_Set
*功能：             设置串口数据位，停止位和效验位
*入口参数：         fd          串口文件描述符
*                   speed       串口速度
*                   flow_ctrl   数据流控制
*                   databits    数据位   取值为 7 或者8
*                   stopbits    停止位   取值为 1 或者2
*                   parity      效验类型 取值为N,E,O,,S
*出口参数：正确返回为1，错误返回为0
*******************************************************************/
static int UART0_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity);

/*******************************************************************
*名称：                UART0_Init()
*功能：                串口初始化
*入口参数：            fd         文件描述符
*                      speed      串口速度
*                      flow_ctrl  数据流控制
*                      databits   数据位   取值为 7 或者8
*                      stopbits   停止位   取值为 1 或者2
*                      parity     效验类型 取值为N,E,O,,S
*
*出口参数：正确返回为1，错误返回为0
*******************************************************************/
static int UART0_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity);

/*******************************************************************
* 名称：            UART0_Recv
* 功能：            接收串口数据
* 入口参数：        fd         文件描述符
*                   rcv_buf    接收串口中数据存入rcv_buf缓冲区中
*                   data_len   一帧数据的长度
* 出口参数：        正确返回为1，错误返回为0
*******************************************************************/
static int UART0_Recv(int fd, char *rcv_buf,int data_len);

/********************************************************************
* 名称：            UART0_Send
* 功能：            发送数据
* 入口参数：        fd           文件描述符
*                   send_buf     存放串口发送数据
*                   data_len     一帧数据的个数
* 出口参数：        正确返回为1，错误返回为0
*******************************************************************/
static int UART0_Send(int fd, char *send_buf,int data_len);

private:
    static Serial* m_instance;

    std::atomic<bool> takeoff;

    std::atomic<bool> TransmitDataReady;

    DoubleBuffer<ReceiveStruct> receiveBuffer;
    DoubleBuffer<SendStruct> transmitBuffer;

    std::string m_SerialPortDevice;
};

#endif